﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;

using SpiritAlight.Stage;
using SpiritAlight;

namespace SpiritAlight.Input
{
    /// <summary>
    /// キーがどのような状態にあるかを表す。
    /// </summary>
    public enum DeviceState
    {
        Error = -1,
        Away = 0,
        Released,
        Pressed,
        Down,
    }


    /// <summary>
    /// マウスのボタンを表す。
    /// </summary>
    public enum MouseButton
    {
        Right,
        Left,
        Middle,
        X1,
        X2,
    }


    public static class InputState
    {
        #region フィールド

        //キーボードとマウスそれぞれ現在の状態と1フレーム前の状態を保存する。
        private static MouseState lastMouse;
        private static MouseState nowMouse;
        private static KeyboardState lastKeyboard;
        private static KeyboardState nowKeyboard;

        #endregion

        #region プロパティ

        public static Vector2 MousePosition
        {
            get { return new Vector2(nowMouse.X, nowMouse.Y); }
        }

        public static int MousePositionX
        {
            get { return nowMouse.X; }
        }

        public static int MousePositionY
        {
            get { return nowMouse.Y; }
        }

        public static Vector2 MoveDistance
        {
            get { return MousePosition - new Vector2(lastMouse.X, lastMouse.Y); }
        }
        #endregion
        /// <summary>
        /// コンストラクタ
        /// </summary>
        static InputState()
        {
            InputState.lastMouse = new MouseState();
            nowMouse = new MouseState();

            lastKeyboard = new KeyboardState();
            nowKeyboard = new KeyboardState();
        }

        #region インデクサ

        /// <summary>
        /// キーボードの状態を返す。
        /// </summary>
        /// <param name="key">状態を確認するキーの種類。</param>
        /// <returns>現在のキーの状態。</returns>
        public static DeviceState IsKeyboard(Keys key)
        {
            //状態に変化がない場合その状態を返す。
            if (lastKeyboard.IsKeyDown(key) ==
                nowKeyboard.IsKeyDown(key))
            {
                if (nowKeyboard.IsKeyDown(key))
                    return DeviceState.Down;
                else
                    return DeviceState.Away;
            }
            else
            {   
                if (nowKeyboard.IsKeyDown(key))
                    return DeviceState.Pressed;
                else
                    return DeviceState.Released;
            }
        }

        /// <summary>
        /// マウスの状態を返す。
        /// </summary>
        /// <param name="Button">状態を確認するボタン。</param>
        /// <returns>ボタンの状態。</returns>
        public static DeviceState IsMouseButton(MouseButton Button)
        {
            switch (Button)
            {
                case MouseButton.Right:
                    return GetButtonState(lastMouse.RightButton, nowMouse.RightButton);
                case MouseButton.Left:
                    return GetButtonState(lastMouse.LeftButton, nowMouse.LeftButton);
                case MouseButton.Middle:
                    return GetButtonState(lastMouse.MiddleButton, nowMouse.MiddleButton);
                case MouseButton.X1:
                    return GetButtonState(lastMouse.XButton1, nowMouse.XButton1);
                case MouseButton.X2:
                    return GetButtonState(lastMouse.XButton2, nowMouse.XButton2);
                default:
                    return DeviceState.Error;
            }
        }

        #endregion

        #region メソッド

        /// <summary>
        /// デバイスの状態を更新する。
        /// </summary>
        public static void Update()
        {
            //1フレーム前の状態を保存。
            lastKeyboard = nowKeyboard;
            lastMouse = nowMouse;

            nowKeyboard = Keyboard.GetState();
            nowMouse = Mouse.GetState();
        }

        /// <summary>
        /// キーボードが押されているかどうかを調べる。
        /// </summary>
        /// <param name="key">押されているかどうか調べるキー。</param>
        /// <returns>押されている場合true、押されていない場合false。</returns>
        public static bool IsDown(Keys key)
        {
            return nowKeyboard.IsKeyDown(key);
        }

        /// <summary>
        /// マウスのボタンが押されているかどうかを調べる。
        /// </summary>
        /// <param name="key">押されているかどうか調べるボタン。</param>
        /// <returns>押されている場合true、押されていない場合false。</returns>
        public static  bool IsDown(MouseButton button)
        {
            return DeviceStateToBool(IsMouseButton(button));
        }
        

        /// <summary>
        /// ボタンの状態をDeviceState型で返す。
        /// </summary>
        /// <param name="lastState">1フレーム前のボタンの状態。</param>
        /// <param name="nowState">現在のボタンの状態。</param>
        /// <returns>現在のボタンの状態。</returns>
        private static DeviceState GetButtonState(ButtonState lastState, ButtonState nowState)
        {
            if (lastState == nowState)
            {
                if (nowState == ButtonState.Pressed)
                    return DeviceState.Down;
                else
                    return DeviceState.Away;
            }
            else
            {
                if (nowState == ButtonState.Pressed)
                    return DeviceState.Pressed;
                else
                    return DeviceState.Released;
            }
        }

        /// <summary>
        /// DeviceStateをboolに変換する。
        /// </summary>
        /// <param name="state">boolに変換するDeviceState。</param>
        /// <returns>boolに変換されたDeviceState。</returns>
        private static bool DeviceStateToBool(DeviceState state)
        {
            switch (state)
            {
                case DeviceState.Away:
                    return false;
                case DeviceState.Released:
                    return false;
                case DeviceState.Pressed:
                    return true;
                case DeviceState.Down:
                    return true;
                default:
                    return false;
            }
        }


        public static Vector2 GlobalMousePosition
        {
            get { return Coordinate.ScreenToGlobal(MousePosition); }
        }

        #endregion

    }
}
